﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Infraestruturex.BaseLibrary;
using Infraestruturex;
using Compilex.Automata;
using Compilex.Syntatic.Descriptors;
using Infraestruturex.Automata;

namespace Compilex.Syntatic
{
    public class Syntatex
    {
        public SyntaticAnalyzer SyntaticAnalyzer { get; set; }
        public SyntaticContext Context { get; set; }
        public string CompiledAssemblyCode
        {
            get { return Context.CommandBlockStack.Current.CodeGenerator.GetCode(); }
        }
        private SemanticActionHooks Hooks { get; set; }

        public Syntatex(SyntaticAnalyzer analyzer)
        {
            this.SyntaticAnalyzer = analyzer;
            this.Context = new SyntaticContext();
            this.Context.TokenProvider = this.SyntaticAnalyzer.TokenProvider;
            this.Hooks = new SemanticActionHooks(this.SyntaticAnalyzer.SemanticActionManager, Context);
            AddStandardLibraryFunctionDescriptors();
        }


        public static Syntatex Build(string input)
        {
            var analyzer = CexSyntaticAnalyzer.GetCexSyntaticAnalyzer();
            analyzer.TokenProvider = new  Automata.Lexer(GetLanguageConfiguration(), input);
            return new Syntatex(analyzer);
        }

        private static Operator[] ParseOperators(string[] lines)
        {
            List<Operator> operators = new List<Operator>();
            foreach (string _operator in lines)
            {
                // OP_ADD +
                string[] elements = _operator.Split(' ');
                operators.Add(new Operator(elements[0], elements[1]));
            }
            return operators.ToArray();
        }


        private static LanguageConfiguration GetLanguageConfiguration()
        {
            string[] keywords = Compilex.Properties.Resource1.keywords.Split(
                new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            string[] operators = Compilex.Properties.Resource1.operators_punctuation.Split(
                new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);
            return new LanguageConfiguration(keywords, ParseOperators(operators));
        }

        private void AddStandardLibraryFunctionDescriptors()
        {
            SymbolTable table = Context.ScopeManager.CurrentScope.SymbolTable;
            AddImprimexIntex(table);
        }

        private void AddImprimexIntex(SymbolTable table)
        {
            FunctionDescriptor descriptor = new FunctionDescriptor();
            descriptor.IsLibraryFunction = true;
            descriptor.IsVoid = true;
            descriptor.Params.Add(new VariableDescriptor(new SymbolType(TypeValue.intex)));

            table.Add("imprimex_intex", new Symbol("imprimex_intex", SymbolClass.Funcex, descriptor));


            descriptor = new FunctionDescriptor();
            descriptor.IsLibraryFunction = true;
            descriptor.IsVoid = false;
            descriptor.ReturnType = new SymbolType(TypeValue.intex);
            table.Add("carreguex_intex", new Symbol("carreguex_intex", SymbolClass.Funcex, descriptor));

        }
    }
}
